package de.uni_saarland.coli.doclists.suffixtree;

import java.io.Serializable;

import de.uni_saarland.coli.doclists.document.IndexDocument;
import de.uni_saarland.coli.doclists.index.Index;
import de.uni_saarland.coli.doclists.index.filesystem.DiscList;
import de.uni_saarland.coli.doclists.index.filesystem.FilesystemHelper;
import de.uni_saarland.coli.doclists.index.filesystem.IToBytes;

/**
 * Edge
 * 
 * stores document start end index of tokens start end node
 * 
 * edges should be created using the EdgeMap Edges have an unique identifier
 * (start node + starting character)
 * 
 * @author stefan
 * 
 */
public class STreeEdge implements IToBytes, Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -9138727667871144115L;
	private int baseDocID;
	private int firstTokenIndex;
	private int firstToken;
	private int lastTokenIndex;
	private int startNode;
	private int endNode;
	private int listIndex;
	protected DiscList parentList;

	public STreeEdge(int docID, int startTokenIndex, int endTokenIndex,
			int startNode, int startToken) {
		this.baseDocID = docID;
		this.firstTokenIndex = startTokenIndex;
		this.lastTokenIndex = endTokenIndex;
		this.startNode = startNode;
		this.firstToken = startToken;
		this.endNode = Index.getNodeMap().createNode().getNodeID();
		this.listIndex = 0;
		this.parentList = null;
	}

	public STreeEdge(byte[] bytes) {

		this.baseDocID = FilesystemHelper.getIntFromByteArray(bytes, 0);
		this.firstToken = FilesystemHelper.getIntFromByteArray(bytes, 4);
		this.firstTokenIndex = FilesystemHelper.getIntFromByteArray(bytes, 8);
		this.lastTokenIndex = FilesystemHelper.getIntFromByteArray(bytes, 12);
		this.startNode = FilesystemHelper.getIntFromByteArray(bytes, 16);
		this.endNode = FilesystemHelper.getIntFromByteArray(bytes, 20);
		this.listIndex = 0;
		this.parentList = null;
	}

	public void extend() {
		if (Index.getDocumentManager().getDocument(this.baseDocID).size() >= this.lastTokenIndex)
			this.lastTokenIndex++;
	}

	public int split(Suffix suffix) {
		Index.getEdgeMap().remove(this);
		int l = suffix.getEnd() - suffix.getStart();
		STreeNode oldNode =	Index.getNodeMap().getNode(getEndNode());
		oldNode.addDoc(suffix.getDocID(), suffix.getStart());
		
		STreeEdge newEdge = Index.getEdgeMap().createEdge(suffix.getDocID(),
				this.firstTokenIndex,
				this.firstTokenIndex + l + 1,
				suffix.getMainNode());
		
		STreeNode newNode = Index.getNodeMap().getNode(newEdge.getEndNode());
		
        Index.getNodeMap().getNode(newEdge.getEndNode()).setSuffixNode(suffix.getMainNode());
        
		//STreeNode node = Index.getNodeMap().getNode(newEdge.getEndNode());
		newNode.addDoc(suffix.getDocID(), this.firstTokenIndex);
		newNode.addDoc(suffix.getDocID(), this.firstTokenIndex +l +1);

        
		this.firstTokenIndex += l + 1;
				
		this.startNode = newEdge.getEndNode();
		this.firstToken = Index.getDocumentManager()
				.getDocument(this.baseDocID).getTermAt(this.firstTokenIndex);

		Index.getEdgeMap().addEdge(this);
		return newEdge.getEndNode();
	}

	public int getBaseDocID() {
		return baseDocID;
	}

	public int getFirstTokenIndex() {
		return firstTokenIndex;
	}

	public int getLastTokenIndex() {
		return lastTokenIndex;
	}

	public void setStartNode(int s) {
		this.startNode = s;
	}

	public int getStartNode() {
		return startNode;
	}

	public int getEndNode() {
		return endNode;
	}

	public int getFirstToken() {
		return firstToken;
	}

	public String getText() {
		IndexDocument doc = Index.getDocumentManager().getDocument(
				this.baseDocID);
		StringBuilder sb = new StringBuilder();
		for (int i = this.firstTokenIndex; i < this.lastTokenIndex; i++) {
			sb.append(Index.getTermDictionary().getValue(doc.getTermAt(i)))
					.append(" ");
		}
		if (sb.length() > 0)
			sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}

	public String getEdgeName() {
		StringBuilder sb = new StringBuilder();
		sb.append("<").append(this.startNode).append(",")
				.append(Index.getTermDictionary().getValue(this.firstToken))
				.append(">");
		return sb.toString();
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(this.getEdgeName()).append(" ");
		sb.append("DOC:").append(this.baseDocID).append(" ");
		sb.append("TS:").append(this.firstTokenIndex).append(" ");
		sb.append("TE:").append(this.lastTokenIndex).append(" ");
		sb.append("NS:").append(this.startNode).append(" ");
		sb.append("NE:").append(this.endNode).append(" ");
		sb.append("Text: ");
		sb.append(this.getText());
		return sb.toString();
	}

	@Override
	public void setListIDX(int idx) {
		this.listIndex = idx;
	}

	@Override
	public int getListIDX() {
		return this.listIndex;
	}

	@Override
	public void setDistList(DiscList list) {
		this.parentList = list;
	}

	@Override
	public byte[] toBytes() {
		byte[] bytes = new byte[24];

		FilesystemHelper.addIntToByteArray(bytes, this.baseDocID, 0);
		FilesystemHelper.addIntToByteArray(bytes, this.firstToken, 4);
		FilesystemHelper.addIntToByteArray(bytes, this.firstTokenIndex, 8);
		FilesystemHelper.addIntToByteArray(bytes, this.lastTokenIndex, 12);
		FilesystemHelper.addIntToByteArray(bytes, this.startNode, 16);
		FilesystemHelper.addIntToByteArray(bytes, this.endNode, 20);

		return bytes;
	}
}
